package aip.core.dao.attachment;

import static org.springframework.util.Assert.hasText;
import static org.springframework.util.Assert.notNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.dao.DataAccessException;
import org.springframework.util.StringUtils;

import aip.core.model.attachment.Attachment;
import aip.core.model.attachment.Photo;

import com.googlecode.horncomb.bean.filter.ConditionSet;
import com.googlecode.horncomb.bean.filter.SimpleMapConditionSet;
import com.googlecode.horncomb.bean.order.DefaultOrder;
import com.googlecode.horncomb.bean.order.DefaultOrderToken;
import com.googlecode.horncomb.bean.order.Order;
import com.googlecode.horncomb.bean.paged.PagedList;
import com.googlecode.horncomb.orm.ibatis.SqlMapEntityDaoImpl;

/**
 * @author
 * @version $LastChangedRevision: 130 $
 */
public class AttachmentDao extends SqlMapEntityDaoImpl<Attachment>
{
    private static final long serialVersionUID = -6965547123103625836L;
    public static final String DFT_FILE_TABLE = "COMM_ATTACHMENT";
    public static final String DFT_REFTABLE_SUFFIX = "_REF";
    private String defaultTableName = DFT_FILE_TABLE;
    private static Map<String, String> attachmentTypeMap = new HashMap<String, String>();
    private static Map<String, String> refEntityTableMap = new HashMap<String, String>();

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("rawtypes")
    @Override
    protected Map buildParam(ConditionSet constraints, Order order)
    {
        if (constraints == null)
        {
            constraints = new SimpleMapConditionSet();
        }
        return super.buildParam(constraints, order);
    }

    /**
     * {@inheritDoc} <br>
     * 保存文件，根据type取得表名
     */
    public void save(Attachment entity) throws DataAccessException
    {
        entity.setTableName(this.getTableName(entity.getType()));
        super.save(entity);
    }

    /**
     * {@inheritDoc} <br>
     * 保存文件，文件内容存与数据库表中的BLOB字段，若是图片附件，同时存储缩略图
     */
    @Override
    public void insert(Attachment entity) throws DataAccessException
    {
        String stmtName = entity.getType().indexOf(Attachment.TYPE_PHOTO) != -1 ? "insertPhoto"
                : "insertWithOutContent";

        super.insert(entity, stmtName);
    }

    /**
     * {@inheritDoc}
     */
    public void insertRef(Attachment entity) throws DataAccessException
    {
        // 保存附件、实体关联，修改了附件中的tableName，需在完成保存附件后执行
        entity.setTableName(getTableNameRef(this.getTableName(entity.getType())));
        this.getSqlMapClientTemplate().insert(
                this.buildStatementName("insertRef"), entity);
    }

    /**
     * {@inheritDoc}
     */
    public void updatePhoto(Photo photo) throws DataAccessException
    {
        photo.setTableName(this.getTableName(photo.getType()));
        this.update(photo, "updatePhotoWithContent");
    }

    /**
     * {@inheritDoc}
     */
    public void deletePhotoContent(int id, String type)
            throws DataAccessException
    {
        hasText(type);
        ConditionSet cons = new SimpleMapConditionSet().addConstraint("id", id)
                .addConstraint("tableName", this.getTableName(type));
        this.doUpdate(cons, null, "deletePhotoContent");
    }

    /**
     * {@inheritDoc}
     */
    public List<? extends Attachment> queryByEntity(int entityRefId, String type)
            throws DataAccessException
    {
        hasText(type);
        ConditionSet constraints = new SimpleMapConditionSet().addConstraint(
                "entityRefId", entityRefId).addConstraint("type", type);
        this.addTableName(constraints, type);
        Order order = new DefaultOrder(new DefaultOrderToken("CREATE_"));
        return super.query(constraints, order);
    }

    /**
     * {@inheritDoc}
     */
    public PagedList<List<? extends Attachment>> queryByEntity(int entityRefId,
            String type, int page, int pageSize) throws DataAccessException
    {
        hasText(type);
        notNull(page);
        notNull(pageSize);
        ConditionSet constraints = new SimpleMapConditionSet().addConstraint(
                "entityRefId", entityRefId).addConstraint("type", type);
        this.addTableName(constraints, type);
        Order order = new DefaultOrder(new DefaultOrderToken("ORDER_"));
        return super.query(constraints, order, page, pageSize);
    }

    /**
     * {@inheritDoc}
     */
    public Attachment getWithContent(String id, String type)
            throws DataAccessException
    {
        hasText(id);
        hasText(type);
        ConditionSet cons = new SimpleMapConditionSet().addConstraint("id", id)
                .addConstraint("type", type)
                .addConstraint("getWithContent", true);
        this.addTableName(cons, type);
        return super.doGet(cons);
    }

    /**
     * {@inheritDoc}
     */
    public Photo getWithThumb(String id, String type)
            throws DataAccessException
    {
        hasText(id);
        hasText(type);
        ConditionSet cons = new SimpleMapConditionSet().addConstraint("id", id)
                .addConstraint("type", type)
                .addConstraint("getWithThumb", true);
        this.addTableName(cons, type);
        return (Photo) super.doGet(cons);
    }

    /**
     * {@inheritDoc}
     */
    public Photo getPrimaryPhoto(int entityRefId, String type)
            throws DataAccessException
    {
        hasText(type);
        List<? extends Attachment> ams = this.queryByEntity(entityRefId, type,
                1, 1).getSource();
        if (ams.isEmpty())
        {
            return null;
        }
        return (Photo) ams.get(0);
    }

    /**
     * {@inheritDoc}
     */
    public void deleteRef(int id, int entityRefId, String type)
    {
        if (this.logger.isDebugEnabled())
        {
            this.logger.debug("delete ref by id: " + id + ", entityRefId:"
                    + entityRefId);
        }
        hasText(type);
        ConditionSet cons = new SimpleMapConditionSet().addConstraint("id", id)
                .addConstraint("entityRefId", entityRefId);
        this.addTableName(cons, type);
        this.doDelete(cons, "deleteRef");
    }

    /**
     * {@inheritDoc}
     */
    public void deleteRefByEntity(String entityRefId, String type)
    {
        if (this.logger.isDebugEnabled())
        {
            this.logger.debug("delete ref by entityRefId:" + entityRefId);
        }
        hasText(entityRefId);
        hasText(type);
        ConditionSet cons = new SimpleMapConditionSet().addConstraint(
                "entityRefId", entityRefId);
        this.addTableName(cons, type);
        this.doDelete(cons, "deleteRef");
    }

    /**
     * {@inheritDoc}
     */
    public void deleteUselessAttachment()
    {
        for (String tableName : refEntityTableMap.keySet())
        {
            String tableNameRef = this.getTableNameRef(tableName);
            String[] refEntityTables = StringUtils.delimitedListToStringArray(
                    refEntityTableMap.get(tableName), ",", " ");

            ConditionSet cons = new SimpleMapConditionSet()
                    .addConstraint("tableName", tableName)
                    .addConstraint("tableNameRef", tableNameRef)
                    .addConstraint("refEntityTables", refEntityTables);
            this.doDelete(cons, "deleteUselessRef");
            this.doDelete(cons, "deleteUseless");
        }
    }

    /**
     * 条件中加入表名
     * @param cons
     * @param type
     */
    private void addTableName(ConditionSet cons, String type)
    {
        String tableName = this.getTableName(type);
        String tableNameRef = this.getTableNameRef(tableName);
        ((SimpleMapConditionSet) cons).addConstraint("tableName", tableName)
                .addConstraint("tableNameRef", tableNameRef);
    }

    /**
     * 根据附件类型获取数据表
     * @param type
     * @return
     */
    private String getTableName(String type)
    {
        String tableName = attachmentTypeMap.get(type);
        if (!StringUtils.hasText(tableName))
        {
            tableName = this.defaultTableName;
        }
        return tableName;
    }

    /**
     * 根据主表名获取中间表
     * @param bizType
     * @return
     */
    private String getTableNameRef(String tableName)
    {
        return tableName.concat(DFT_REFTABLE_SUFFIX);
    }

    public void setDefaultTableName(String defaultTableName)
    {
        this.defaultTableName = defaultTableName;
    }

    public void setAttachmentTypeMap(Map<String, String> map)
    {
        attachmentTypeMap = map;
    }

    public void setRefEntityTableMap(Map<String, String> map)
    {
        refEntityTableMap = map;
    }

}
